package com.lianqi.emcpframework.dataaccess;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.Function;

import javax.annotation.PreDestroy;

import com.lianqi.emcpframework.utils.ThreadLocalUtils;

/**
 * @program emcp-framework
 * @ClassName AuthenticationHolder
 * @description: 权限holder 用于静态方式获取当前登录用户的权限
 * @author: sky
 * @create: 2018/11/28 10:57
 */
public final class DataAccessContextHolder {

    private static final List<DataAccessContextSupplier> suppliers = new ArrayList<>();
    private static final ReadWriteLock lock = new ReentrantReadWriteLock();
    public static final String CURRENT_CONTEXT_KEY = DataAccessContextHolder.class.getName() + "_current_context_id";

    private static ConcurrentMap<Serializable, DataAccessContext> dataAccessContextMap = new ConcurrentHashMap<>();

    /**
     * 获取权限上下文
     * 
     * @param function
     * @return
     */
    private static DataAccessContext get(Function<DataAccessContextSupplier, DataAccessContext> function) {
        lock.readLock().lock();
        try {
            return suppliers.stream().map(function).filter(Objects::nonNull).findFirst().orElse(null);
        } finally {
            lock.readLock().unlock();
        }
    }

    /**
     * 获取当前数据谦虚上下文
     * 
     * @return
     */
    public static DataAccessContext get() {
        Serializable contextId = getCurrentContextId();
        if (contextId != null) {
            return get(contextId);
        }
        return get(supplier -> supplier.get());
    }

    public static Serializable getCurrentContextId() {
        return ThreadLocalUtils.get(CURRENT_CONTEXT_KEY);
    }

    /**
     * 根据数据权限上下文标识 获取数据权限上线文
     * 
     * @param contextId
     * @return
     */
    private static DataAccessContext get(Serializable contextId) {
        if (dataAccessContextMap.containsKey(contextId)) {
            return dataAccessContextMap.get(contextId);
        } else {
            DataAccessContext context = get(supplier -> supplier.get());
            dataAccessContextMap.put(contextId, context);
            return context;
        }

    }

    /**
     * 初始化 添加权限上下文提供者
     * 
     * @param supplier
     */
    public static void addSupplier(DataAccessContextSupplier supplier) {
        lock.writeLock().lock();
        try {
            suppliers.add(supplier);
        } finally {
            lock.writeLock().unlock();
        }
    }

    /**
     * 删除缓存的数据权限上下文
     * 
     * @param contextId
     */
    public static void remove(Serializable contextId) {
        dataAccessContextMap.remove(contextId);
    }

    /**
     * 清理方法
     */
    @PreDestroy
    public static void clear() {
        dataAccessContextMap = null;
    }

    /**
     * 设置当前数据权限上下文标识
     * 
     * @param contextId
     */
    public static void bindCurrentContextId(Serializable contextId) {
        ThreadLocalUtils.put(CURRENT_CONTEXT_KEY, contextId);
    }

    /**
     * 清除当前数据权限上下文标识
     *
     */
    public static void unbindCurrentContextId() {
        ThreadLocalUtils.remove(CURRENT_CONTEXT_KEY);
    }
}
